/**
* Copyright (c) 2005-2011 by Appcelerator, Inc. All Rights Reserved.
* Licensed under the terms of the Eclipse Public License (EPL).
* Please see the license.txt included with this distribution for details.
* Any modifications to this file must keep this entire header intact.
*/
/*
* @author: fabioz
* Created: January 2004
*/
package org.python.pydev.editor.actions;
import java.util.HashSet;
import java.util.Set;
import org.eclipse.core.resources.IFile;
import org.eclipse.jface.action.Action;
import org.eclipse.jface.action.IAction;
import org.eclipse.jface.text.BadLocationException;
import org.eclipse.jface.text.IDocument;
import org.eclipse.jface.text.IRegion;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.ui.IEditorActionDelegate;
import org.eclipse.ui.IEditorInput;
import org.eclipse.ui.IEditorPart;
import org.eclipse.ui.IEditorReference;
import org.eclipse.ui.IWorkbench;
import org.eclipse.ui.IWorkbenchPage;
import org.eclipse.ui.IWorkbenchWindow;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.texteditor.ITextEditor;
import org.eclipse.ui.texteditor.ITextEditorExtension;
import org.eclipse.ui.texteditor.ITextEditorExtension2;
import org.python.pydev.core.docutils.PySelection;
import org.python.pydev.core.log.Log;
import org.python.pydev.editor.PyEdit;
import com.aptana.shared_core.string.FastStringBuffer;
/**
* @author Fabio Zadrozny
*
* Superclass of all our actions. Contains utility functions.
*
* Subclasses should implement run(IAction action) method.
*/
public abstract class PyAction extends Action implements IEditorActionDelegate {
protected PyAction() {
super();
}
protected PyAction(String text, int style) {
super(text, style);
}
public static Shell getShell() {
IWorkbenchWindow activeWorkbenchWindow = getActiveWorkbenchWindow();
if (activeWorkbenchWindow == null) {
Log.log("Error. Not currently with thread access (so, there is no activeWorkbenchWindow available)");
return null;
}
return activeWorkbenchWindow.getShell();
}
/**
* @return the active workbench window or null if it's not available.
*/
public static IWorkbenchWindow getActiveWorkbenchWindow() {
IWorkbench workbench = PlatformUI.getWorkbench();
if (workbench == null) {
return null;
}
IWorkbenchWindow activeWorkbenchWindow = workbench.getActiveWorkbenchWindow();
return activeWorkbenchWindow;
}
// Always points to the current editor
protected volatile IEditorPart targetEditor;
public void setEditor(IEditorPart targetEditor) {
this.targetEditor = targetEditor;
}
/**
* This is an IEditorActionDelegate override
*/
public void setActiveEditor(IAction action, IEditorPart targetEditor) {
setEditor(targetEditor);
}
/**
* Activate action (if we are getting text)
*/
public void selectionChanged(IAction action, ISelection selection) {
action.setEnabled(true);
}
public static String getDelimiter(IDocument doc) {
return PySelection.getDelimiter(doc);
}
/**
* This function returns the text editor.
*/
protected ITextEditor getTextEditor() {
if (targetEditor instanceof ITextEditor) {
return (ITextEditor) targetEditor;
} else {
throw new RuntimeException("Expecting text editor. Found:" + targetEditor.getClass().getName());
}
}
/**
* @return python editor.
*/
protected PyEdit getPyEdit() {
if (targetEditor instanceof PyEdit) {
return (PyEdit) targetEditor;
} else {
throw new RuntimeException("Expecting PyEdit editor. Found:" + targetEditor.getClass().getName());
}
}
/**
* @return true if the contents of the editor may be changed. Clients MUST call this before actually
* modifying the editor.
*/
protected boolean canModifyEditor() {
ITextEditor editor = getTextEditor();
if (editor instanceof ITextEditorExtension2) {
return ((ITextEditorExtension2) editor).isEditorInputModifiable();
} else if (editor instanceof ITextEditorExtension) {
return !((ITextEditorExtension) editor).isEditorInputReadOnly();
} else if (editor != null) {
return editor.isEditable();
}
//If we don't have the editor, let's just say it's ok (working on document).
return true;
}
/**
* Helper for setting caret
* @param pos
* @throws BadLocationException
*/
protected void setCaretPosition(int pos) throws BadLocationException {
getTextEditor().selectAndReveal(pos, 0);
}
/**
* Are we in the first char of the line with the offset passed?
* @param doc
* @param cursorOffset
*/
protected void isInFirstVisibleChar(IDocument doc, int cursorOffset) {
try {
IRegion region = doc.getLineInformationOfOffset(cursorOffset);
int offset = region.getOffset();
String src = doc.get(offset, region.getLength());
if ("".equals(src))
return;
int i = 0;
while (i < src.length()) {
if (!Character.isWhitespace(src.charAt(i))) {
break;
}
i++;
}
setCaretPosition(offset + i - 1);
} catch (BadLocationException e) {
beep(e);
return;
}
}
/**
* Returns the position of the last non whitespace char in the current line.
* @param doc
* @param cursorOffset
* @return position of the last character of the line (returned as an absolute
* offset)
*
* @throws BadLocationException
*/
protected int getLastCharPosition(IDocument doc, int cursorOffset) throws BadLocationException {
IRegion region;
region = doc.getLineInformationOfOffset(cursorOffset);
int offset = region.getOffset();
String src = doc.get(offset, region.getLength());
int i = src.length();
boolean breaked = false;
while (i > 0) {
i--;
//we have to break if we find a character that is not a whitespace or a tab.
if (Character.isWhitespace(src.charAt(i)) == false && src.charAt(i) != '\t') {
breaked = true;
break;
}
}
if (!breaked) {
i--;
}
return (offset + i);
}
/**
* Goes to first char of the line.
* @param doc
* @param cursorOffset
*/
protected void gotoFirstChar(IDocument doc, int cursorOffset) {
try {
IRegion region = doc.getLineInformationOfOffset(cursorOffset);
int offset = region.getOffset();
setCaretPosition(offset);
} catch (BadLocationException e) {
beep(e);
}
}
/**
* Goes to the first visible char.
* @param doc
* @param cursorOffset
*/
protected void gotoFirstVisibleChar(IDocument doc, int cursorOffset) {
try {
setCaretPosition(PySelection.getFirstCharPosition(doc, cursorOffset));
} catch (BadLocationException e) {
beep(e);
}
}
/**
* Goes to the first visible char.
* @param doc
* @param cursorOffset
*/
protected boolean isAtFirstVisibleChar(IDocument doc, int cursorOffset) {
try {
return PySelection.getFirstCharPosition(doc, cursorOffset) == cursorOffset;
} catch (BadLocationException e) {
return false;
}
}
//================================================================
// HELPER FOR DEBBUGING...
//================================================================
/*
* Beep...humm... yeah....beep....ehehheheh
*/
protected static void beep(Exception e) {
try {
PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell().getDisplay().beep();
} catch (IllegalStateException x) {
//ignore, workbench has still not been created
}
Log.log(e);
}
/**
*
*/
public static String getLineWithoutComments(String sel) {
return sel.replaceAll("#.*", "");
}
/**
*
*/
public static String getLineWithoutComments(PySelection ps) {
return getLineWithoutComments(ps.getCursorLineContents());
}
/**
* Counts the number of occurences of a certain character in a string.
*
* @param line the string to search in
* @param c the character to search for
* @return an integer (int) representing the number of occurences of this character
*/
public static int countChars(char c, String line) {
int ret = 0;
int len = line.length();
for (int i = 0; i < len; i++) {
if (line.charAt(i) == c) {
ret += 1;
}
}
return ret;
}
/**
* Counts the number of occurences of a certain character in a string.
*
* @param line the string to search in
* @param c the character to search for
* @return an integer (int) representing the number of occurences of this character
*/
public static int countChars(char c, StringBuffer line) {
int ret = 0;
int len = line.length();
for (int i = 0; i < len; i++) {
if (line.charAt(i) == c) {
ret += 1;
}
}
return ret;
}
/**
* Counts the number of occurences of a certain character in a string.
*
* @param line the string to search in
* @param c the character to search for
* @return an integer (int) representing the number of occurences of this character
*/
public static int countChars(char c, FastStringBuffer line) {
int ret = 0;
int len = line.length();
for (int i = 0; i < len; i++) {
if (line.charAt(i) == c) {
ret += 1;
}
}
return ret;
}
public static String lowerChar(String s, int pos) {
char[] ds = s.toCharArray();
ds[pos] = Character.toLowerCase(ds[pos]);
return new String(ds);
}
/**
* @param string
* @param j
* @return
*/
public static boolean stillInTok(String string, int j) {
char c = string.charAt(j);
return c != '\n' && c != '\r' && c != ' ' && c != '.' && c != '(' && c != ')' && c != ',' && c != ']'
&& c != '[' && c != '#';
}
/**
* @param ps the selection that contains the document
*/
protected void revealSelEndLine(PySelection ps) {
// Put cursor at the first area of the selection
int docLen = ps.getDoc().getLength() - 1;
IRegion endLine = ps.getEndLine();
if (endLine != null) {
int curOffset = endLine.getOffset();
getTextEditor().selectAndReveal(curOffset < docLen ? curOffset : docLen, 0);
}
}
/**
* @return a set with the currently opened files in the PyEdit editors.
*/
public static Set<IFile> getOpenFiles() {
Set<IFile> ret = new HashSet<IFile>();
IWorkbenchWindow activeWorkbenchWindow = getActiveWorkbenchWindow();
if (activeWorkbenchWindow == null) {
return ret;
}
IWorkbenchPage[] pages = activeWorkbenchWindow.getPages();
for (int i = 0; i < pages.length; i++) {
IEditorReference[] editorReferences = pages[i].getEditorReferences();
for (int j = 0; j < editorReferences.length; j++) {
IEditorReference iEditorReference = editorReferences[j];
if (!PyEdit.EDITOR_ID.equals(iEditorReference.getId())) {
continue; //Only PyDev editors...
}
try {
IEditorInput editorInput = iEditorReference.getEditorInput();
if (editorInput == null) {
continue;
}
IFile file = (IFile) editorInput.getAdapter(IFile.class);
if (file != null) {
ret.add(file);
}
} catch (Exception e1) {
Log.log(e1);
}
}
}
return ret;
}
}